#include "CodeGen.hpp"
#include "CodeGenUtil.hpp"

#include <algorithm>
#include <cstdint>
#include <cstring>
#include <string>
#include <sys/types.h>
#include <utility>
#include <vector>


void CodeGen::allocate() {
    unsigned offset = PROLOGUE_OFFSET_BASE;

    // 为每个参数分配栈空间（如果没有被分配寄存器）
    for (auto &arg : context.func->get_args()) {
        auto size = arg.get_type()->get_size();
        offset = ALIGN(offset + size, size);
        context.offset_map[&arg] = -static_cast<int>(offset);
    }

    // 为每条指令结果分配栈空间
    for (auto &bb : context.func->get_basic_blocks()) {
        for (auto &instr : bb.get_instructions()) {
            // 每个非 void 的定值都分配栈空间
            if (not instr.is_void()) {
                auto size = instr.get_type()->get_size();
                offset = ALIGN(offset + size, size);
                context.offset_map[&instr] = -static_cast<int>(offset);
            }

            // 为数组 alloca 分配额外空间（不对齐）
            if (instr.is_alloca()) {
                auto *alloca_inst = static_cast<AllocaInst *>(&instr);
                auto alloc_size = alloca_inst->get_alloca_type()->get_size();
                offset += alloc_size;
                context.array_start_offset[alloca_inst] = offset;
            }
        }
    }

    // 最终的帧大小对齐为 16 的倍数
    context.frame_size = ALIGN(offset, PROLOGUE_ALIGN);
}

void CodeGen::gen_prologue() {
    makeSureInRange("addi", SP, SP, -context.frame_size, "add");
    makeSureInRange("sd", RA_reg, SP, context.frame_size - 8, "stx");
    makeSureInRange("sd", FP, SP, context.frame_size - 16, "stx");
    makeSureInRange("addi", FP, SP, context.frame_size, "add");
    // 将函数参数转移到栈帧上
    int garg_cnt = 0;
    int farg_cnt = 0;
    for (auto &arg : context.func->get_args()) {
        if (arg.get_type()->is_float_type()) {
            store_from_freg(&arg, FReg::fa(farg_cnt++));
        } else { // int or pointer
            store_from_greg(&arg, Reg::a(garg_cnt++));
        }
    }
    
}

void CodeGen::gen_epilogue() {
    // TODO1:根据你的理解实现函数的 epilogue
    // 提示：可能包括的步骤：恢复ra、恢复s0、恢复sp、返回到调用方
    // 恢复ra寄存器
    makeSureInRange("ld", RA_reg, SP, context.frame_size - 8, "ldx");
    // 恢复fp寄存器
    makeSureInRange("ld", FP, SP, context.frame_size - 16, "ldx");
    // 恢复栈指针
    makeSureInRange("addi", SP, SP, context.frame_size, "add");
    // 返回到调用方
    append_inst("ret");
    //TODO1-------------end
}

// 将一个值 val 加载到目标通用寄存器 reg 中
void CodeGen::load_to_greg(Value *val, const Reg &reg) {
    assert(val->get_type()->is_integer_type() ||
           val->get_type()->is_pointer_type());

    if (auto *constant = dynamic_cast<ConstantInt *>(val)) {// 如果 val 是一个常数整数
        int32_t val = constant->get_value();
        if (IS_IMM_12(val)) {
            append_inst(ADDI, {reg.print(), "zero", std::to_string(val)});
        } else {
            load_large_int32(val, reg);// 如果常数太大，用 load_large_int32 处理
        }
    } else if (auto *global = dynamic_cast<GlobalVariable *>(val)) { // 如果是全局变量，生成地址加载指令
        append_inst(LOAD_ADDR, {reg.print(), global->get_name()});
    } else { //剩余情况从栈中加载到寄存器
        load_from_stack_to_greg(val, reg);
    }
}


// 加载一个 32 位大整数到寄存器（通常是伪指令 li 会被展开成 lui+addi）
void CodeGen::load_large_int32(int32_t val, const Reg &reg) {
    append_inst(LI, {reg.print(), std::to_string(val)});
}

// 加载一个 64 位整数到寄存器，先加载高 32 位并左移，再加载低 32 位
void CodeGen::load_large_int64(int64_t val, const Reg &reg) {
    auto low_32 = static_cast<int32_t>(val & LOW_32_MASK); // 提取低 32 位
    auto high_32 = static_cast<int32_t>(val >> 32); // 提取高 32 位
    load_large_int32(high_32, reg); 
    append_inst(SLLI, {reg.print(), reg.print(), "32"}); // 加载高 32 位并左移 32 位
    load_large_int32(low_32, reg);// 覆盖写入低 32 位
}

// 从栈帧中加载某个变量 val 到通用寄存器 reg 中
void CodeGen::load_from_stack_to_greg(Value *val, const Reg &reg) {
    // 获取该变量在当前函数栈帧中的偏移
    auto offset = context.offset_map.at(val);
    auto offset_str = std::to_string(offset);
    auto *type = val->get_type(); // 获取该变量的类型（用于确定加载指令）
    if (IS_IMM_12(offset)) { // 如果 offset 能够用 12 位立即数表示，可以直接使用 offset(fp) 格式访问内存
        if (type->is_int1_type()) {
            append_inst(LOAD_BYTE, {reg.print(), "fp", offset_str});
        } else if (type->is_int32_type()) {
            append_inst(LOAD_WORD, {reg.print(), "fp", offset_str});
        } else { // Pointer
            append_inst(LOAD_DOUBLE, {reg.print(), "fp", offset_str});
        }
    } else { // 如果偏移过大，不能直接编码到指令中，先将 offset 加载到寄存器
        load_large_int64(offset, reg); // reg = offset
        append_inst(ADD, {reg.print(), "fp", reg.print()}); // reg = fp + offset
        if (type->is_int1_type()) {
            append_inst(LOAD_BYTE, {reg.print(), reg.print(), "0"});
        } else if (type->is_int32_type()) {
            append_inst(LOAD_WORD, {reg.print(), reg.print(), "0"});
        } else { // Pointer
            append_inst(LOAD_DOUBLE, {reg.print(), reg.print(), "0"});
        }
    }
}



// 将通用寄存器 reg 中的值存储到 val 对应的栈上位置（以 fp 为基址）
void CodeGen::store_from_greg(Value *val, const Reg &reg) {
    // 获取该变量在当前函数栈帧中的偏移
    auto offset = context.offset_map.at(val);
    auto offset_str = std::to_string(offset);
    auto *type = val->get_type(); // 获取该变量的类型（用于确定加载指令）
    if (IS_IMM_12(offset)) { // 如果 offset 能够用 12 位立即数表示，可以直接使用 offset(fp) 格式访问内存
        if (type->is_int1_type()) {
            append_inst(STORE_BYTE, {reg.print(), "fp", offset_str});
        } else if (type->is_int32_type()) {
            append_inst(STORE_WORD, {reg.print(), "fp", offset_str});
        } else { // Pointer
            append_inst(STORE_DOUBLE, {reg.print(), "fp", offset_str});
        }
    } else { // 对于 offset 超出立即数范围的情况，需要通过地址计算访问
        auto addr = Reg::s(11); // 使用临时寄存器 s11 作为中间地址计算（可更换）
        load_large_int64(offset, addr);
        append_inst(ADD , {addr.print(), "fp", addr.print()});
        if (type->is_int1_type()) {
            append_inst(STORE_BYTE, {reg.print(), addr.print(), "0"});
        } else if (type->is_int32_type()) {
            append_inst(STORE_WORD, {reg.print(), addr.print(), "0"});
        } else { // Pointer
            append_inst(STORE_DOUBLE, {reg.print(), addr.print(), "0"});
        }
    }
}

// 将一个浮点类型的 Value 加载到浮点寄存器 freg 中
void CodeGen::load_to_freg(Value *val, const FReg &freg) {
    assert(val->get_type()->is_float_type());
    if (auto *constant = dynamic_cast<ConstantFP *>(val)) {  // 若是浮点常量，加载立即数
        float val = constant->get_value();
        load_float_imm(val, freg);
    } else { // 从栈中加载浮点变量
        auto offset = context.offset_map.at(val);
        auto offset_str = std::to_string(offset);
        if (IS_IMM_12(offset)) {
            append_inst(FLOAD_SINGLE, {freg.print(), "fp", offset_str});
        } else { // 偏移过大，使用寄存器间接寻址
            auto addr = Reg::s(11); // 临时通用寄存器 s11
            load_large_int64(offset, addr);  // 加载偏移
            append_inst(ADD, {addr.print(), "fp", addr.print()}); // addr = fp + offset
            append_inst(FLOAD_SINGLE, {freg.print(), addr.print(), "0"});  // 从 addr 加载
        }
    }
}

// 将 float 常量加载进浮点寄存器 freg
void CodeGen::load_float_imm(float val, const FReg &r) {
    int32_t bytes = *reinterpret_cast<int32_t *>(&val);  // 将 float 解释为 32 位整数（IEEE 754 bit pattern）
    load_large_int32(bytes, Reg::s(11));
    append_inst("fmv.s.x", {r.print(), Reg::s(11).print()}); // 使用 fmv.s.x 指令将整数位模式转成 float 放入 freg
}

// 将浮点寄存器 r 中的值存储回栈中 val 对应的位置
void CodeGen::store_from_freg(Value *val, const FReg &r) {
    auto offset = context.offset_map.at(val);
    if (IS_IMM_12(offset)) {
        auto offset_str = std::to_string(offset);
        append_inst(FSTORE_SINGLE, {r.print(), "fp", offset_str});
    } else { // 偏移过大，需要间接寻址
        auto addr = Reg::s(11);
        load_large_int64(offset, addr);
        append_inst(ADD, {addr.print(), "fp", addr.print()});  // addr = fp + offset
        append_inst(FSTORE_SINGLE, {r.print(), addr.print(), "0"}); // 从 r 存到 addr
    }
}


void CodeGen::gen_ret() {
    // TODO2：函数返回操作，你需要思考如何处理返回值(a0/fa0)，如何返回到调用者（可以使用j指令、context中或许有你需要的信息）
    auto *retInst = static_cast<ReturnInst *>(context.inst);
    if (retInst->is_void_ret()) {
        // 如果是void返回，直接生成epilogue
        gen_epilogue();
    } else {
        // 获取返回值
        auto *retVal = retInst->get_operand(0);
        // 根据返回值类型，将其加载到相应的返回值寄存器中
        if (retVal->get_type()->is_float_type()) {
            // 浮点类型返回值，加载到fa0
            load_to_freg(retVal, FReg::fa(0));
        } else {
            // 整数或指针类型返回值，加载到a0
            load_to_greg(retVal, Reg::a(0));
        }
        // 生成epilogue
        gen_epilogue();
    }
    // TODO2----------------end
}

void CodeGen::gen_br() {
    auto *branchInst = static_cast<BranchInst *>(context.inst);
    if (branchInst->is_cond_br()) {
        // TODO6：补全条件跳转操作
        // 提示： 根据条件表达式的结果（reg t1 != 0），选择跳转到 true 分支或 false 分支。
        //       你可能会用到blt、j等指令
        // 获取条件表达式的值
        auto *cond = branchInst->get_operand(0);
        load_to_greg(cond, Reg::t(1)); // 将条件加载到t1寄存器

        // 获取true分支和false分支的基本块
        auto *true_bb = static_cast<BasicBlock *>(branchInst->get_operand(1));
        auto *false_bb = static_cast<BasicBlock *>(branchInst->get_operand(2));

        // 如果条件不为0，跳转到true分支，否则跳转到false分支
        append_inst("bne t1, zero, " + label_name(true_bb)); // 如果t1 != 0，跳转到true分支
        append_inst("j " + label_name(false_bb)); // 否则跳转到false分支
        // TODO6-------------------end
    } else {
        // 无条件跳转
        auto *branchbb = static_cast<BasicBlock *>(branchInst->get_operand(0));
        append_inst("j " + label_name(branchbb)); // 跳转到目标基本块
    }
}

void CodeGen::gen_binary() {  
    // 分别将左右操作数加载到 t0 t1
    load_to_greg(context.inst->get_operand(0), Reg::t(0));
    load_to_greg(context.inst->get_operand(1), Reg::t(1));
    // 根据指令类型生成汇编
    switch (context.inst->get_instr_type()) {
    case Instruction::add:
        output.emplace_back("add t2, t0, t1");
        break;
    case Instruction::sub:
        output.emplace_back("sub t2, t0, t1");
        break;
    case Instruction::mul:
        output.emplace_back("mul t2, t0, t1");
        break;
    case Instruction::sdiv:
        output.emplace_back("div t2, t0, t1");
        break;
    case Instruction::srem:
        output.emplace_back("remw t2, t0, t1");
        break;
    default:
        assert(false);
    }
    // 将结果填入栈帧中
    store_from_greg(context.inst, Reg::t(2));
}

void CodeGen::gen_alloca() {
    auto *alloca_inst = static_cast<AllocaInst *>(context.inst);
    auto shuzu_offset = context.array_start_offset[alloca_inst];
    std::string temp_reg = "t1";  
    // 加载偏移量到临时寄存器
    load_large_int32(shuzu_offset, Reg::t(0));
    // 计算栈地址：fp - shuzu_offset
    append_inst(SUB + string(" ") + temp_reg + ", fp, t0");
    store_from_greg(context.inst, Reg::t(1));
}

void CodeGen::gen_load() {
    auto ptr = context.inst->get_operand(0);//在指针类型auto*和auto没有任何区别
    auto *type = context.inst->get_type();
    load_to_greg(ptr, Reg::t(0));
    std::string sreg ="t0";
    if (type->is_float_type()) {
        std::string dest="ft0";
        append_inst(FLOAD_SINGLE,{dest, sreg, "0"});//ft0=M[t0+0]
        store_from_freg(context.inst, FReg::ft(0));
    } else {
        // TODO3: 补全load整型变量的情况，考虑int1 int32 int64
        std::string dest_reg = "t0";
        // 根据类型选择不同的加载指令
        if (type->is_int1_type()) {
            // 加载布尔值(1字节)
            append_inst(LOAD_BYTE, {dest_reg, sreg, "0"});
        } else if (type->is_int32_type()) {
            // 加载32位整数
            append_inst(LOAD_WORD, {dest_reg, sreg, "0"});
        } else {
            // 加载64位整数或指针
            append_inst(LOAD_DOUBLE, {dest_reg, sreg, "0"});
        }
        // 将结果存入栈帧
        store_from_greg(context.inst, Reg::t(0));
    }
}

void CodeGen::gen_store() {
    auto *type = context.inst->get_operand(0)->get_type();//怎么store取决于我们要存的数据是什么类型
    auto *ptr = context.inst->get_operand(1);//位置
    auto *data = context.inst->get_operand(0);//要存入的值
    load_to_greg(ptr, Reg::t(1)); 
    auto pst_reg=std::string("t1");
    if (type->is_float_type()) {
        load_to_freg(data, FReg::ft(0)); 
        append_inst(FSTORE_SINGLE ,{"ft0", pst_reg , "0"});//M[t1+0]=ft0
    } else {
        if(type->is_int1_type()){
            load_to_greg(data, Reg::t(0)); 
            append_inst("sb "+std::string("t0")+", "+ "0("+pst_reg+")");//M[t1+0]=t0
        }else if(type->is_int32_type()){
            load_to_greg(data, Reg::t(0)); 
            append_inst("sw "+std::string("t0")+", "+ "0("+pst_reg+")");
        }else{
            load_to_greg(data, Reg::t(0)); 
            append_inst("sd "+std::string("t0")+", "+ "0("+pst_reg+")");
        }
    }

}

void CodeGen::gen_icmp() {
    //这个指令有两个参数，就是两个参与运算的参数
    auto sreg0=std::string("t0");
    auto sreg1=std::string("t1");
    load_to_greg(context.inst->get_operand(0), Reg::t(0));  // Operand 1
    load_to_greg(context.inst->get_operand(1), Reg::t(1));  // Operand 2
    auto dest_reg = std::string("t0");
    // 根据指令类型生成汇编
    switch (context.inst->get_instr_type()) {
    case Instruction::eq:
        append_inst("slt s11,"+sreg1+","+sreg0);
        append_inst("slt t0,"+sreg0+","+sreg1);
        append_inst("or t0,t0,s11");
        append_inst("addi s11,zero,1");
        append_inst("sub  "+dest_reg+",s11,t0");
        break;
    case Instruction::ne:
        append_inst("slt s11,"+sreg1+","+sreg0);
        append_inst("slt t0,"+sreg0+","+sreg1);
        append_inst("or "+dest_reg+",t0,s11");
        break;
    case Instruction::gt:
        append_inst("slt "+dest_reg+","+sreg1+","+sreg0);
        break;
    case Instruction::ge:
        append_inst("slt "+dest_reg+","+sreg0+","+sreg1);
        append_inst("addi s11,zero,1");
        append_inst("sub "+dest_reg+",s11,"+dest_reg);
        break;
    case Instruction::lt:
          append_inst("slt "+dest_reg+","+sreg0+","+sreg1);
        break;
    case Instruction::le:
        append_inst("slt "+dest_reg+","+sreg1+","+sreg0);
        append_inst("addi s11,zero,1");
        append_inst("sub "+dest_reg+",s11,"+dest_reg);
        break;
    default:
        assert(false);
    }
    store_from_greg(context.inst,Reg::t(0));
    
}



void CodeGen::gen_fcmp() {
    // TODO7: 补全各种浮点型变量比较的情况（对应的Light IR：feq/fne/fgt/fge/flt/fle）
    // 提示： 你可能会用到 feq.s、flt.s、fle.s、xori等指令
    // 加载两个操作数到浮点寄存器
    auto sreg0 = std::string("ft0");
    auto sreg1 = std::string("ft1");
    load_to_freg(context.inst->get_operand(0), FReg::ft(0));  // 操作数1
    load_to_freg(context.inst->get_operand(1), FReg::ft(1));  // 操作数2
    auto dest_reg = std::string("t0");  // 结果存储在整型寄存器中

    // 根据指令类型生成汇编
    switch (context.inst->get_instr_type()) {
    case Instruction::feq:
        // 浮点数相等比较
        append_inst("feq.s " + dest_reg + ", " + sreg0 + ", " + sreg1);
        break;
    case Instruction::fne:
        // 浮点数不等比较：先比较相等，然后取反
        append_inst("feq.s " + dest_reg + ", " + sreg0 + ", " + sreg1);
        append_inst("xori " + dest_reg + ", " + dest_reg + ", 1");  // 取反结果
        break;
    case Instruction::fgt:
        // 浮点数大于比较：使用flt.s但交换操作数顺序
        append_inst("flt.s " + dest_reg + ", " + sreg1 + ", " + sreg0);
        break;
    case Instruction::fge:
        // 浮点数大于等于比较：使用fle.s但交换操作数顺序
        append_inst("fle.s " + dest_reg + ", " + sreg1 + ", " + sreg0);
        break;
    case Instruction::flt:
        // 浮点数小于比较
        append_inst("flt.s " + dest_reg + ", " + sreg0 + ", " + sreg1);
        break;
    case Instruction::fle:
        // 浮点数小于等于比较
        append_inst("fle.s " + dest_reg + ", " + sreg0 + ", " + sreg1);
        break;
    default:
        assert(false);
    }

    // 将结果存入栈帧
    store_from_greg(context.inst, Reg::t(0));
    // TODO7----------------end
}
void CodeGen::gen_float_binary() {
    auto sreg0=std::string("ft0");
    auto sreg1=std::string("ft1");
    load_to_freg(context.inst->get_operand(0), FReg::ft(0));  // Operand 1
    load_to_freg(context.inst->get_operand(1), FReg::ft(1));  // Operand 2
    auto dest_reg = std::string("ft0");
    // 根据指令类型生成汇编
    switch (context.inst->get_instr_type()) {
    case Instruction::fadd:
        output.emplace_back("fadd.s "+dest_reg+","+sreg0+","+sreg1);
        break;
    case Instruction::fsub:
        output.emplace_back("fsub.s "+dest_reg+","+sreg0+","+sreg1);
        break;
    case Instruction::fmul:
        output.emplace_back("fmul.s "+dest_reg+","+sreg0+","+sreg1);
        break;
    case Instruction::fdiv:
        output.emplace_back("fdiv.s "+dest_reg+","+sreg0+","+sreg1);
        break;
    default:
        assert(false);
    }
    // 将结果填入栈帧中
    store_from_freg(context.inst,FReg::ft(0));
}


void CodeGen::gen_zext() {
    auto sreg0=std::string("t0");
    auto dest_reg = std::string("t0");
    auto *type = context.inst->get_type();
    if (type->is_float_type()) {
        sreg0=std::string("ft0");
        load_to_freg(context.inst->get_operand(0), FReg::ft(0));  // Operand 1
        dest_reg=std::string("ft0");
        append_inst(GR2FR + string(" ")+sreg0+","+dest_reg);//放到合适的位置
    } else {
        load_to_greg(context.inst->get_operand(0), Reg::t(0));  // Operand 1
        if (type->is_int8_type()) {
            append_inst("andi " + dest_reg + ", " + sreg0 + ", 0xff");
        } else if (type->is_int16_type()) {
            append_inst("andi " + dest_reg + ", " + sreg0 + ", 0xffff");
        }else if(sreg0!=dest_reg){
            append_inst("add "+dest_reg+", zero, "+sreg0);
        }
    }
    if(type->is_float_type()){
        store_from_freg(context.inst,FReg::ft(0));
    }else{
        store_from_greg(context.inst,Reg::t(0));
    }

}

void CodeGen::gen_call() {
    auto *callInst = static_cast<CallInst *>(context.inst);
    auto retType = callInst->get_function_type()->get_return_type();
    int gregs = 0; // 通用寄存器参数计数器
    int fregs = 0; // 浮点寄存器参数计数器

    // 处理函数参数，按照类型加载到相应的寄存器
    for (auto& arg : callInst->get_operands()) {
        auto argType = arg->get_type();
        if (argType->is_float_type()) {
            load_to_freg(arg, FReg::fa(fregs++)); // 加载到浮点寄存器
        } else if (argType->is_pointer_type() || argType->is_integer_type()) {
            load_to_greg(arg, Reg::a(gregs++)); // 加载到通用寄存器
        }
    }

    // 生成函数调用指令
    append_inst("jal " + callInst->get_operand(0)->get_name());

    // 根据返回值类型选择寄存器存储返回值
    if (retType->is_float_type()) {
        store_from_freg(callInst, FReg::fa(0)); // 浮点返回值
    } else if (retType->is_integer_type()) {
        store_from_greg(callInst, Reg::a(0)); // 整数返回值
    }
}


/* 
 * %op = getelementptr [10 x i32], [10 x i32]* %op, i32 0, i32 %op  //多维数组访问
 * %op = getelementptr        i32,        i32* %op, i32 %op         //一维数组/直接访问指针
 *
 * Memory layout
 *       -            ^
 * +-----------+      | 低地址
 * |  arg ptr  |---+  |  //arg ptr 是你传给 GEP 的起始指针（基准地址）
 * +-----------+   |  |
 * |           |   |  |
 * +-----------+   /  |
 * |           |<--   |
 * |           |   \  |
 * |           |   |  |  //Array 是连续内存的数组区域，GEP 会根据偏移量在这里面计算具体元素地址。
 * |   Array   |   |  |
 * |           |   |  |
 * |           |   |  |
 * |           |   |  |
 * +-----------+   |  |
 * |  Pointer  |---+  |  //Pointer 表示计算完地址后的结果，即 GEP 的结果（往往是你要访问或存储的内存地址）。
 * +-----------+      |
 * |           |      |
 * +-----------+      |
 * |           |      |
 * +-----------+      |
 * |           |      |
 * +-----------+      | 高地址
 *       +
 */
void CodeGen::gen_gep() {
    auto *gepInst = static_cast<GetElementPtrInst *>(context.inst);
    int len = gepInst->get_num_operand(); // 操作数个数，包含指针 + 若干维度的下标
    std::vector<Value *> ops = gepInst->get_operands(); // 获取所有操作数
    
    if (len >= 3) { // 多维数组访问，例如 %op = getelementptr [10 x i32], [10 x i32]* %op, i32 0, i32 %op
        // 处理多维数组
        // 加载基准指针到寄存器 t1
        load_to_greg(ops[0], Reg::t(1));
        // 初始化类型追踪
        Type *current_type = ops[0]->get_type()->get_pointer_element_type();
        int dimension = 0; // 当前维度

        // 预计算各维度步长（反向计算）
        std::vector<unsigned> strides;
        while (current_type->is_array_type()) {
            auto *array_type = static_cast<ArrayType*>(current_type); // 安全转换
            strides.push_back(array_type->get_num_of_elements());
            current_type = array_type->get_element_type();
        }
        strides.push_back(1);
        // std::reverse(strides.begin(), strides.end()); // 转为正序

        // 处理每个索引（从第二个下标开始，跳过第一个通常为0的下标）
        for (size_t i = 2; i < ops.size(); ++i) {
            load_to_greg(ops[i], Reg::t(0));
            auto elem_size = gepInst->get_element_type()->get_size();
            load_large_int32(elem_size, Reg::s(11));
            // 计算当前维度步长 = 后续所有维度元素数 * 元素大小
            unsigned stride = 1;
            for (size_t j = dimension + 1; j < strides.size(); ++j) {
                stride *= strides[j];
            }
            load_large_int32(stride, Reg::s(10));
            append_inst("mul t0, t0, s10");
            append_inst("mul t0, t0, s11"); // t0 = idx * stride
            append_inst("add t1, t1, t0");  // 累加到基地址
            dimension++;                    // 移动到下一维度
        }
        // 存储最终地址
        store_from_greg(context.inst, Reg::t(1));
    } else { // 形如a[i]的访问，或访问指针
        auto dest_reg = std::string("t0");
        auto *ptr = context.inst->get_operand(0); // 指针
        auto ptr_reg = std::string("t1");
        load_to_greg(ptr, Reg::t(1));  // 加载基准地址
        auto *idx = context.inst->get_operand(1); // 下标
        auto idx_reg = std::string("t0"); // 这个是常数，也就是数组下标
        load_to_greg(idx, Reg::t(0));   // 加载下标值
        // 以下三条指令实现乘以 4（即元素大小为 4 的简化情况）：
        append_inst("add s11, " + idx_reg + ", " + idx_reg); // s11 = 2 * idx
        append_inst("add s11, s11, s11"); // s11 = 4 * idx
        // t0 = ptr_reg + s11，即最终地址 = 原始地址 + 偏移
        append_inst("add " + dest_reg + ", s11, " + ptr_reg);
        // 把t0里存的最终地址存回栈帧的对应位置
        store_from_greg(context.inst, Reg::t(0));
    }
}

void CodeGen::gen_sitofp() {
    auto *itfInst = static_cast<SiToFpInst *>(context.inst);
    std::vector<Value *> ops=itfInst->get_operands();
    auto sreg0=std::string("t0");
    load_to_greg(context.inst->get_operand(0),Reg::t(0)); 
    auto dest_reg= std::string("ft0");
    append_inst(GR2FR ,{dest_reg, sreg0});
    store_from_freg(context.inst,FReg::ft(0));
}

void CodeGen::gen_fptosi() {
    // TODO8: 浮点数转向整数，注意向下取整(rtz)，你可能会用到指令fcvt.w.s
    auto *ftiInst = static_cast<FpToSiInst *>(context.inst);
    std::vector<Value *> ops = ftiInst->get_operands();
    auto sreg0 = std::string("ft0");
    load_to_freg(context.inst->get_operand(0), FReg::ft(0)); 
    auto dest_reg = std::string("t0");
    // 使用fcvt.w.s指令将浮点数转换为整数，rtz表示向0舍入模式
    append_inst("fcvt.w.s " + dest_reg + ", " + sreg0 + ", rtz");
    store_from_greg(context.inst, Reg::t(0));
    // TODO8--------------------end
}
void CodeGen::global_array_int(ConstantArray * init_val){//全局整型数组变量
    /*示例输出 int a[5]={0,1,2,3,4};
                .data
                .globl	a
                .align	3
                .type	a, @object
                .size	a, 20
            a:
                .word	0
                .word	1
                .word	2
                .word	3
                .word	4
                */
    for (unsigned i = 0; i < init_val->get_size_of_array(); i++)
    {//获得这一层的大小
        Constant *element = init_val->get_element_value(i);
        if (!dynamic_cast<ConstantArray *>(element))
        {//这个元素已经不再是array了
            auto *IntVal = static_cast<ConstantInt *>(element);
            append_inst(".word", {std::to_string(IntVal->get_value())},
                            ASMInstruction::Atrribute);
        }else{
            //这个元素依然是array，递归下去
            auto new_array=static_cast<ConstantArray *>(element);
            global_array_int(new_array);
        }
    }
}

void CodeGen::global_array_float(ConstantArray * init_val){
    /*示例输出 float a[3]={1.01,4.11,13.99};
                .data
                .globl	a
                .align	3
                .type	a, @object
                .size	a, 12
            a:
                .word 1065437102 //float 1.01
                .word 1082361119 //float 4.11
                .word 1096800010 //float 13.99
                */
    // TODO5-2:完善浮点型全局数组变量初始化
    // 提示:可以参考global_array_int的实现
    for (unsigned i = 0; i < init_val->get_size_of_array(); i++) {
        Constant *element = init_val->get_element_value(i);
        if (!dynamic_cast<ConstantArray *>(element)) {
            // 这个元素已经不再是array了，是浮点数
            auto *FloatVal = static_cast<ConstantFP *>(element);
            // 获取浮点值
            float float_val = FloatVal->get_value();
            // 将浮点值转换为整数位模式
            int32_t int_bits = *reinterpret_cast<int32_t*>(&float_val);
            // 使用.word存储浮点数的位模式
            append_inst(".word", {std::to_string(int_bits)}, ASMInstruction::Atrribute);
        } else {
            // 这个元素依然是array，递归下去
            auto new_array = static_cast<ConstantArray *>(element);
            global_array_float(new_array);
        }
    }
    // TODO5-2------------------end
}
void CodeGen::run() {
    // 确保每个函数中基本块的名字都被设置好
    m->set_print_name();

    /* 使用 GNU 伪指令为全局变量分配空间
     * 你可以使用 `la` 指令将标签 (全局变量) 的地址载入寄存器中, 比如
     * 要将 `a` 的地址载入 t0, 只需要 `la t0, a`
     * 由于在IR自动化生成阶段，我们为无初始值的全局变量分配了0作为初始值，因此在目标代码生成阶段，全局变量都有初始值
     */
    if (!m->get_global_variable().empty()) {
        append_inst("Global variables", ASMInstruction::Comment);
        /*
         * 虽然可以使用 `.bss` 伪指令为未初始化数据分配空间，
         * 我们依然显式指定 `.data` 段，这是因为：
         * 
         * - `.data` 更加通用，与标准 RISC-V 编译器行为一致；
         * - `.bss` 虽然常用于未初始化数据，但某些旧版本 GNU 汇编器对其支持不完善；
         * - 显式使用  `.data` 能更好地控制输出段结构。
         */
        append_inst(".text", ASMInstruction::Atrribute);
        append_inst(".data",ASMInstruction::Atrribute);

        for (auto &global : m->get_global_variable()) { //给全局变量分配空间
            if(global.get_type()->get_pointer_element_type()->is_integer_type()){//处理整数型全局变量
                auto *IntVal = static_cast<ConstantInt *>(global.get_init());
                /* 输出形式示例：
                .globl  a
                .align  2
                .type   a, @object
                .size   a, 4
                a:
                .word   5
                */
                auto size =
                global.get_type()->get_pointer_element_type()->get_size();
                append_inst(".globl", {global.get_name()},
                            ASMInstruction::Atrribute);
                append_inst(".align 2",
                            ASMInstruction::Atrribute); // 对齐到 4 字节           
                append_inst(".type", {global.get_name(), "@object"},
                            ASMInstruction::Atrribute);
                append_inst(".size", {global.get_name(), std::to_string(size)},
                            ASMInstruction::Atrribute);
                append_inst(global.get_name(), ASMInstruction::Label);
                append_inst(".word", {std::to_string(IntVal->get_value())},
                            ASMInstruction::Atrribute);
            }else if(global.get_type()->get_pointer_element_type()->is_array_type()){ //处理数组类型全局变量
                 /* 输出形式示例：
                    .globl	a
                    .data
                    .align	3
                    .type	a, @object
                    .size	a, 20
                a:
                    .word	0
                    .word	1
                    .word	2
                    .word	3
                    .word	4
                    */
                if(global.get_type()->get_pointer_element_type()->get_array_element_type()->is_integer_type()){ //整型数组
                    auto size =
                        global.get_type()->get_pointer_element_type()->get_size();
                    append_inst(".globl", {global.get_name()},
                                ASMInstruction::Atrribute);
                    append_inst(".align 3",
                                ASMInstruction::Atrribute); // 对齐到 8 字节          
                    append_inst(".type", {global.get_name(), "@object"},
                                ASMInstruction::Atrribute);
                    append_inst(".size", {global.get_name(), std::to_string(size)},
                                ASMInstruction::Atrribute);
                    append_inst(global.get_name(), ASMInstruction::Label);

                    if(dynamic_cast<ConstantZero *>(global.get_init())){
                        // 初始化值为 0，使用 `.space` 节省空间
                        append_inst(".space", {std::to_string(size)}, ASMInstruction::Atrribute);              

                    }else{
                        //如果不是0
                        auto *IntVal = static_cast<ConstantArray *>(global.get_init());
                        global_array_int(IntVal);
                    }
                }else{ //浮点型数组
                    // TODO5-1:完善浮点型全局数组变量声明及其初始化
                    // 提示：你可能需要将初始化值不为0的浮点型全局数组变量的处理逻辑封装到global_array_float函数中，因此可能需要完成TODO5-2，即填充global_array_float函数
                    //      当然你也可以直接在当前else分支内处理，弃用global_array_float函数（对应的TODO5-2也不用完成）
                    auto size = global.get_type()->get_pointer_element_type()->get_size();
                    append_inst(".globl", {global.get_name()}, ASMInstruction::Atrribute);
                    append_inst(".align 3", ASMInstruction::Atrribute); // 对齐到 8 字节          
                    append_inst(".type", {global.get_name(), "@object"}, ASMInstruction::Atrribute);
                    append_inst(".size", {global.get_name(), std::to_string(size)}, ASMInstruction::Atrribute);
                    append_inst(global.get_name(), ASMInstruction::Label);

                    if (dynamic_cast<ConstantZero *>(global.get_init())) {
                        // 初始化值为 0，使用 `.space` 节省空间
                        append_inst(".space", {std::to_string(size)}, ASMInstruction::Atrribute);
                    } else {
                        // 如果不是0，使用global_array_float函数处理
                        auto *FloatArrayVal = static_cast<ConstantArray *>(global.get_init());
                        global_array_float(FloatArrayVal);
                    }
                    // TODO5-1------------------end
                }    
            }else if(global.get_type()->get_pointer_element_type()->is_float_type()){ //浮点型全局变量
                /* 输出形式示例： float a=1.01;
                .globl  a
                .align  2
                .type   a, @object
                .size   a, 4
                a:
                .word   1065437102    // float 1.01
                */
                // TODO4:完善浮点型全局变量声明及其初始化
                // 提示：RISC-V 中没有 .float 指令，需手动将 float 转换为 int 再用 .word 表示原始比特位
                //      可以使用 reinterpret_cast<int&>(float) 实现 float → int 的位级转换
                auto *FloatVal = static_cast<ConstantFP *>(global.get_init());
                auto size = global.get_type()->get_pointer_element_type()->get_size();
                // 获取浮点值
                float float_val = FloatVal->get_value();
                // 将浮点值转换为整数位模式
                int32_t int_bits = *reinterpret_cast<int32_t*>(&float_val);

                // 生成汇编指令
                append_inst(".globl", {global.get_name()}, ASMInstruction::Atrribute);
                append_inst(".align 2", ASMInstruction::Atrribute); // 对齐到 4 字节           
                append_inst(".type", {global.get_name(), "@object"}, ASMInstruction::Atrribute);
                append_inst(".size", {global.get_name(), std::to_string(size)}, ASMInstruction::Atrribute);
                append_inst(global.get_name(), ASMInstruction::Label);
                // 使用.word存储浮点数的位模式
                append_inst(".word", {std::to_string(int_bits)}, ASMInstruction::Atrribute);
                // TODO4--------------------------end
            }
        }
    }

    // 函数代码段
    append_inst(".text", ASMInstruction::Atrribute);
    append_inst(".align 2",ASMInstruction::Atrribute);  
    for (auto &func : m->get_functions()) {

        if (not func.is_declaration()) {


            // 更新 context
            context.clear();
            context.func = &func;

            // 函数信息
            append_inst(".globl", {func.get_name()}, ASMInstruction::Atrribute);
            append_inst(".type", {func.get_name(), "@function"},
                        ASMInstruction::Atrribute);
            append_inst(func.get_name(), ASMInstruction::Label);

            // 分配函数栈帧
            allocate();
            // 生成 prologue
            gen_prologue();
            //处理bb
            
            for (auto &bb : func.get_basic_blocks()) {
                context.bb = &bb;
                append_inst(label_name(context.bb), ASMInstruction::Label);
                for (auto &instr : bb.get_instructions()) {
                    // For debug
                    append_inst(instr.print(), ASMInstruction::Comment);
                    context.inst = &instr; // 更新 context
                    switch (instr.get_instr_type()) {
                        case Instruction::ret:
                            gen_ret();
                            break;
                        case Instruction::br:
                            gen_br();
                            break;
                        case Instruction::add:
                        case Instruction::sub:
                        case Instruction::mul:
                        case Instruction::sdiv:
                        case Instruction::srem:
                            gen_binary();
                            break;
                        case Instruction::fadd:
                        case Instruction::fsub:
                        case Instruction::fmul:
                        case Instruction::fdiv:
                            gen_float_binary();
                            break;
                        case Instruction::alloca:
                            gen_alloca();
                            break;
                        case Instruction::load:
                            gen_load();
                            break;
                        case Instruction::store:
                            gen_store();
                            break;
                        case Instruction::ge:
                        case Instruction::gt:
                        case Instruction::le:
                        case Instruction::lt:
                        case Instruction::eq:
                        case Instruction::ne:
                            gen_icmp();
                            break;
                        case Instruction::fge:
                        case Instruction::fgt:
                        case Instruction::fle:
                        case Instruction::flt:
                        case Instruction::feq:
                        case Instruction::fne:
                            gen_fcmp();
                            break;
                        case Instruction::phi:
                            break;
                        case Instruction::call:
                            gen_call();
                            break;
                        case Instruction::getelementptr:
                            gen_gep();
                            break;
                        case Instruction::zext:
                            gen_zext();
                            break;
                        case Instruction::fptosi:
                            gen_fptosi();
                            break;
                        case Instruction::sitofp:
                            gen_sitofp();
                            break;
                        default:
                            assert(false && "Unhandled instruction type");
                    }
                }
            }
            // 生成 epilogue
            gen_epilogue();
        }
    }
}

std::string CodeGen::print() const {
    std::string result;
    for (const auto &inst : output) {
        result += inst.format();
    }
    auto sub = result.find("memset_int");
    while (sub != string::npos) {
        result.replace(sub, 10, "memset");
        sub = result.find("memset_int");
    }

    sub = result.find("memset_float");
    while (sub != string::npos) {
        result.replace(sub, 12, "memset");
        sub = result.find("memset_float");
    }
    return result;
}

